package http;

import com.beeboxes.utils.MD5Utils;
import org.apache.log4j.Logger;
import org.apaches.commons.codec.digest.DigestUtils;

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @function 大文件传输。 success
 * okhttp 失败。
 */
public class HttpURLConnectionPostFile {
    //MultipartEntityBuilder
    private static final int TIME_OUT = 1000 * 200;                          //超时时间
    private static final String CHARSET = "utf-8";                         //编码格式
    private static final String PREFIX = "--";                            //前缀
    private static final String BOUNDARY = UUID.randomUUID().toString();  //边界标识 随机生成
    private static final String CONTENT_TYPE = "multipart/form-data";     //内容类型
    private static final String LINE_END = "\r\n";                        //换行
    public static String testUrl = "http://localhost:9090/task/api/uploadLog?uname=aaa&pwd=bbb&sn=FC6N2219230048&taskNo=300";
    private static final Logger logger = Logger.getLogger(HttpURLConnectionPostFile.class);
    private static final String localTestUpLoadFile = "/Users/macpro/Downloads/BXMJ_2G_DVT_2.6.2.62.d.s.u_11092317-ota.zip";

    public static void main(String[] args) {
        logger.info("main: ");
        File file = new File(localTestUpLoadFile);
        Map<String, String> strParams = new HashMap<>();
        strParams.put("someinfo", "hello server");

        try {
            String s = DigestUtils.md5Hex(new FileInputStream(localTestUpLoadFile));
            logger.info("main: md5:"+s);
        } catch (IOException e) {
            e.printStackTrace();
        }

        Map<String, File> fileMap = new HashMap<>();
        String md5 = MD5Utils.encrypt(localTestUpLoadFile);
        logger.info("main:md5: "+md5);
        fileMap.put("File-"+md5, file);
//        postRequest(strParams, fileMap);

//        postRequest(testUrl,localTestUpLoadFile);
    }

    public static void postRequest(String originUrl,String filePath) {
        logger.info("postRequest: 1");
        File file = new File(filePath);
        Map<String, File> fileMap = new HashMap<>();
        String md5 = MD5Utils.encrypt(filePath);
        logger.info("postRequest:md5: "+md5);
        fileMap.put("File-"+md5, file);
        postRequest(originUrl,null, fileMap);
    }

    public static void postRequest(final String originUrl,final Map<String, String> strParams, final Map<String, File> fileParams) {
        logger.info("postRequest: 2");
        new Thread(new Runnable() {
            public void run() {
                try {
                    trustAllHttpsCertificates();
                    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                        public boolean verify(String urlHostName, SSLSession session) {
                            return true;
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }

                HttpURLConnection conn = null;
                try {
                    URL url = new URL(originUrl);
                    conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("POST");
                    conn.setReadTimeout(TIME_OUT);
                    conn.setConnectTimeout(TIME_OUT);
                    conn.setChunkedStreamingMode(51200);//分块大小
                    conn.setDoOutput(true);
                    conn.setDoInput(true);
                    conn.setUseCaches(false);//Post 请求不能使用缓存
                    //设置请求头参数
                    conn.setRequestProperty("Connection", "Keep-Alive");
                    conn.setRequestProperty("Charset", "UTF-8");
                    conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);

                    //请求体
                    //上传参数
                    DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
                    //add someParams
                    if (strParams != null) {
                        dos.writeBytes(getStrParams(strParams).toString());
                        dos.flush();
                    }

                    //文件上传
                    if (fileParams!=null && fileParams.size()>0) {
                        StringBuilder fileSb = new StringBuilder();
                        for (Map.Entry<String, File> fileEntry : fileParams.entrySet()) {
                            fileSb.append(PREFIX)
                                    .append(BOUNDARY)
                                    .append(LINE_END)
                                    /**
                                     * 这里重点注意： name里面的值为服务端需要的key 只有这个key 才可以得到对应的文件
                                     * filename是文件的名字，包含后缀名的 比如:abc.png
                                     */
                                    .append("Content-Disposition: form-data; name=\"file\"; filename=\""
                                            + fileEntry.getKey() + "\"" + LINE_END)
                                    .append("Content-Type: " + CONTENT_TYPE + LINE_END) //此处的ContentType不同于 请求头 中Content-Type
                                    .append("Content-Transfer-Encoding: 8bit" + LINE_END)
                                    .append(LINE_END);// 参数头设置完以后需要两个换行，然后才是参数内容
                            dos.writeBytes(fileSb.toString());
                            dos.flush();
                            InputStream is = new FileInputStream(fileEntry.getValue());
                            byte[] buffer = new byte[1024];
                            int len = 0;
                            while ((len = is.read(buffer)) != -1) {
                                dos.write(buffer, 0, len);
                            }
                            is.close();
                            dos.writeBytes(LINE_END);
                        }
                        //请求结束标志
                        dos.writeBytes(PREFIX + BOUNDARY + PREFIX + LINE_END);
                        dos.flush();
                    }
                    dos.close();
                    System.out.println("postResponseCode() = " + conn.getResponseCode());
                    //读取服务器返回信息
                    if (conn.getResponseCode() == 200) {
                        InputStream in = conn.getInputStream();
                        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                        String line = null;
                        StringBuilder response = new StringBuilder();
                        while ((line = reader.readLine()) != null) {
                            response.append(line);
                        }
                        System.out.println("run: " + response);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (conn != null) {
                        conn.disconnect();
                    }
                }
            }
        }).start();
    }


    //add some Params
    private static StringBuilder getStrParams(Map<String, String> strParams) {
        StringBuilder strSb = new StringBuilder();
        for (Map.Entry<String, String> entry : strParams.entrySet()) {
            strSb.append(PREFIX)
                    .append(BOUNDARY)
                    .append(LINE_END)
                    .append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINE_END)
                    .append("Content-Type: text/plain; charset=" + CHARSET + LINE_END)
                    .append("Content-Transfer-Encoding: 8bit" + LINE_END)
                    .append(LINE_END)// 参数头设置完以后需要两个换行，然后才是参数内容
                    .append(entry.getValue())
                    .append(LINE_END);
        }
        return strSb;
    }


    private static void trustAllHttpsCertificates() throws NoSuchAlgorithmException, KeyManagementException {
        TrustManager[] trustAllCerts = new TrustManager[1];
        trustAllCerts[0] = new TrustAllManager();
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    private static class TrustAllManager implements X509TrustManager {
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
        }

        public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
        }
    }


}
